import {
    providers,
    Overrides,
    PayableOverrides,
    CallOverrides,
    BigNumber,
    BigNumberish 
} from 'ethers';

import { MonkeyKing, MonkeyKing__factory } from '../../types';
import { IMonkeyKingClient } from "./IMonkeyKing-client";
import { EtherERC721Client } from './ethers-ERC721-client';


export class EtherMonkeyKingClient extends EtherERC721Client implements IMonkeyKingClient{
    public monkeyKing: MonkeyKing | undefined;//typechain 合约

    public connectProvider(address: string, provider: providers.Provider){
        super.connectProvider(address,provider);
        this.provider = provider;
        this.monkeyKing = MonkeyKing__factory.connect(address,this.provider);
    }

    public contract(): Promise<MonkeyKing> {
        if (this.provider === undefined || this.monkeyKing === undefined) {
          return Promise.reject('need to connect a valid provider');
        }
        return Promise.resolve(this.monkeyKing);
    }

    public getArrtibutesFactory(
        config?: CallOverrides
      ): Promise<[string, string, string, string, string, string, string, string, string]>  
    {
        if (this.provider === undefined || this.monkeyKing === undefined) {
            return Promise.reject('need to connect a valid provider');
        }
        return this.monkeyKing.getArrtibutesFactory({...config});
    }

    public getCurrentIssue(config?: CallOverrides): Promise<BigNumber>{
        if (this.provider === undefined || this.monkeyKing === undefined) {
            return Promise.reject('need to connect a valid provider');
        }
        return this.monkeyKing.getCurrentIssue({...config});
    }

    public getIssueTotal(config?: CallOverrides): Promise<BigNumber>{
        
        if (this.provider === undefined || this.monkeyKing === undefined) {
            return Promise.reject('need to connect a valid provider');
        }
        return this.monkeyKing.getIssueTotal({...config});
    }

    public getMonkeyKing(tokenId : BigNumberish,config ?:PayableOverrides) : 
    Promise<{ tokenId: BigNumber; contractAddr: string }[]>
    {
        if (this.provider === undefined || this.monkeyKing === undefined) {
            return Promise.reject('need to connect a valid provider');
        }
        return this.monkeyKing.getMonkeyKing(tokenId,{...config});
    }

    public async initArrtibutesFactory(
        arrtibutes: [string, string, string, string, string, string ,string, string, string],
        config ?:PayableOverrides
    ):Promise<any>
    {
        if (
            this.provider === undefined ||
            this.monkeyKing === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        const gas = await this.monkeyKing
        .connect(this.signer)
        .estimateGas.initArrtibutesFactory(arrtibutes, { ...config });

        const transaction = await this.monkeyKing
        .connect(this.signer)
        .initArrtibutesFactory(arrtibutes, { gasLimit: gas.mul(13).div(10), ...config });
        
        const receipt = await transaction.wait(this._waitConfirmations);
        return receipt;
        
    }


    public async newArrtibutesFactorys(
        config?: Overrides & { from?: string | Promise<string> }
      ): Promise<any>{
        if (
            this.provider === undefined ||
            this.monkeyKing === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        const gas = await this.monkeyKing
        .connect(this.signer)
        .estimateGas.newArrtibutesFactorys({ ...config });

        const transaction = await this.monkeyKing
        .connect(this.signer)
        .newArrtibutesFactorys( { gasLimit: gas.mul(13).div(10), ...config });
        
        const receipt = await transaction.wait(this._waitConfirmations);
        return receipt;
      }

    public async SafeMint(
        to: string,
        arrtibutes: [
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string },
            { tokenId: BigNumberish; contractAddr: string }
        ],
        config:PayableOverrides
    ): Promise<any>
    {
        if (
            this.provider === undefined ||
            this.monkeyKing === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        const gas = await this.monkeyKing
        .connect(this.signer)
        .estimateGas.SafeMint(to,arrtibutes, { ...config });

        const transaction = await this.monkeyKing
        .connect(this.signer)
        .SafeMint(to,arrtibutes, { gasLimit: gas.mul(13).div(10), ...config });
        
        const receipt = await transaction.wait(this._waitConfirmations);
        return receipt;
    }

    public async ChangeArrtibute(
        monkeyKingTokenId: BigNumberish,
        option: BigNumberish,
        _newtokenId: BigNumberish,
        newContractAddr: string,
        config:PayableOverrides
    ):Promise<any>
    {
        if (
            this.provider === undefined ||
            this.monkeyKing === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        const gas = await this.monkeyKing
        .connect(this.signer)
        .estimateGas.ChangeArrtibute(monkeyKingTokenId,option,_newtokenId,newContractAddr, { ...config });

        const transaction = await this.monkeyKing
        .connect(this.signer)
        .ChangeArrtibute(monkeyKingTokenId,option,_newtokenId,newContractAddr, { gasLimit: gas.mul(13).div(10), ...config });
        
        const receipt = await transaction.wait(this._waitConfirmations);
        return receipt;
    }



}